<template>
  <div class="form-single-fragment third-party-dlg" style="position: relative">
    <div class="section-title">
      <span>参数设置</span>
    </div>

    <el-form
      ref="form"
      :model="formData"
      class="full-width-input"
      :rules="rules"
      label-width="120px"
      :size="formItemSize"
      label-position="right"
      @submit.prevent
    >
      <el-row :gutter="20">
        <el-col v-for="param in apiParams" :key="param.paramName" :span="12">
          <el-form-item
            :label="param.paramName"
            :prop="'params.' + param.paramName"
            :rules="[
              {
                required: param.required,
                message: `请输入${param.paramDesc || param.paramName}`,
                trigger: 'blur',
              },
              {
                // 如果param.paramType是String，那么输入的值必须被单引号或者双引号包裹的验证
                validator: (rule, value, callback) => {
                  paramValueVerify(param, rule, value, callback);
                },
                trigger: 'blur',
              },
            ]"
          >
            <el-tooltip :content="param.paramDesc" placement="top" :disabled="!param.paramDesc">
              <!-- 根据参数类型渲染不同的输入控件 -->
              <template v-if="param.paramType === 'String'">
                <el-input
                  v-model="formData.params[param.paramName]"
                  :placeholder="'请输入' + (param.paramDesc || param.paramName)"
                >
                  <template #append>
                    <el-tag size="small">{{ param.paramType }}</el-tag>
                  </template>
                </el-input>
              </template>
              <template v-else-if="param.paramType === 'Number'">
                <!-- <el-input-number 
                  v-model="formData.params[param.paramName]" 
                  :placeholder="'请输入' + (param.paramDesc || param.paramName)"
                  style="width: 100%"
                  clearable
                /> -->
                <el-input
                  v-model.number="formData.params[param.paramName]"
                  :placeholder="'请输入' + (param.paramDesc || param.paramName)"
                >
                  <template #append>
                    <el-tag size="small">{{ param.paramType }}</el-tag>
                  </template>
                </el-input>
              </template>
              <template v-else-if="param.paramType === 'Boolean'">
                <div class="boolean-wrapper">
                  <el-switch v-model="formData.params[param.paramName]" />
                  <el-tag size="small" style="margin-left: 8px">{{ param.paramType }}</el-tag>
                </div>
              </template>
              <template v-else-if="param.paramType === 'Date'">
                <el-date-picker
                  v-model="formData.params[param.paramName]"
                  type="datetime"
                  :placeholder="'请选择' + (param.paramDesc || param.paramName)"
                  style="width: 100%"
                />
              </template>
            </el-tooltip>
            <!--  Jie. 20250804 移动位置，否则无法换行 -->
            <el-input
              v-if="param.paramType === 'Object' || param.paramType === 'Array'"
              v-model="formData.params[param.paramName]"
              type="textarea"
              :autosize="{ minRows: 1 }"
              :placeholder="'请输入' + (param.paramDesc || param.paramName) + '(JSON格式)'"
            >
            </el-input>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>

    <div class="action-bar">
      <el-checkbox v-model="saveParamsLocal">保存参数至本地</el-checkbox>
      <el-button type="primary" @click="onRunScript">运行脚本</el-button>
    </div>

    <div class="section-title">
      <span>运行结果</span>
    </div>

    <div class="result-wrapper">
      <JsonViewer
        v-if="hasResult"
        theme="my-awesome-json-theme"
        copyable
        v-model:value="parsedResult"
        :expand-depth="8"
        boxed
      />
      <el-empty v-else description="暂无运行结果" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { VideoPlay, Setting, Document } from '@element-plus/icons-vue';
import JsonViewer from 'vue-json-viewer';
import { DialogProp } from '@/components/Dialog/types';
import { ANY_OBJECT } from '@/types/generic';
import { useThirdParty } from '@/components/thirdParty/hooks';
import { ThirdProps } from '@/components/thirdParty/types';
import { OnlineApi } from '@/types/online/script';
import { useLayoutStore } from '@/store';
import OnlineApiController from '@/api/online/OnlineApiController';

interface IProps extends ThirdProps {
  rowData?: OnlineApi;
  // 当使用Dialog.show弹出组件时，须定义该prop属性，以便对dialog进行回调
  dialog?: DialogProp<ANY_OBJECT>;
}

const props = defineProps<IProps>();
const { thirdParams } = useThirdParty(props);
const layoutStore = useLayoutStore();

const formItemSize = computed(() => {
  return layoutStore.defaultFormItemSize;
});

const form = ref();
const runResult = ref<ANY_OBJECT | string>('');

const hasResult = computed(() => {
  return runResult.value !== '';
});

const parsedResult = computed(() => {
  if (!runResult.value) return {};
  try {
    return typeof runResult.value === 'string' ? JSON.parse(runResult.value) : runResult.value;
  } catch (e) {
    return runResult.value;
  }
});

const rules = {};

const formData = reactive<{
  params: Record<string, unknown>;
}>({
  params: {},
});

const dialogParams = computed(() => {
  return {
    formData: props.rowData || thirdParams.value.rowData,
  };
});

// 解析脚本参数配置
const apiParams = computed(() => {
  const extraData = dialogParams.value.formData?.extraData;
  if (!extraData) return [];
  try {
    return JSON.parse(extraData);
  } catch (e) {
    console.error('解析脚本参数配置失败:', e);
    return [];
  }
});

const PARAM_STORAGE_PREFIX = 'api_params_';

const saveParamsLocal = ref(false);

// 从本地存储加载参数
const loadParamsFromLocal = () => {
  const apiCode = dialogParams.value.formData?.apiCode;
  if (!apiCode) return;

  const storageKey = PARAM_STORAGE_PREFIX + apiCode;
  const savedParams = localStorage.getItem(storageKey);
  if (savedParams) {
    try {
      const params = JSON.parse(savedParams);
      formData.params = params;
      saveParamsLocal.value = true;
    } catch (e) {
      console.error('加载本地参数失败:', e);
    }
  }
};

// 保存参数到本地存储
const saveParamsToLocal = () => {
  const apiCode = dialogParams.value.formData?.apiCode;
  if (!apiCode) return;

  const storageKey = PARAM_STORAGE_PREFIX + apiCode;
  if (saveParamsLocal.value) {
    localStorage.setItem(storageKey, JSON.stringify(formData.params));
  } else {
    localStorage.removeItem(storageKey);
  }
};

const paramValueVerify = (param, rule, value, callback) => {
  if (param.paramType === 'String' && !/^['"].*['"]$/.test(value)) {
    callback(new Error('字符串必须被单引号或者双引号包裹'));
  } else {
    callback();
  }
};

// 监听保存参数选项变化
watch(saveParamsLocal, newVal => {
  saveParamsToLocal();
});

// 监听参数变化，如果选中了保存选项，则自动保存
watch(
  () => formData.params,
  () => {
    if (saveParamsLocal.value) {
      saveParamsToLocal();
    }
  },
  { deep: true },
);

onMounted(() => {
  // 加载本地保存的参数
  loadParamsFromLocal();
});

// 运行脚本
const onRunScript = () => {
  form.value.validate((valid: boolean) => {
    if (!valid) return;

    try {
      // 处理参数，将字符串类型的对象/数组转换为实际的JSON对象
      const processedParams = { ...formData.params };
      for (const param of apiParams.value) {
        if (
          (param.paramType === 'Object' || param.paramType === 'Array') &&
          processedParams[param.paramName]
        ) {
          try {
            processedParams[param.paramName] = JSON.parse(
              processedParams[param.paramName] as string,
            );
          } catch (e) {
            ElMessage.error(`参数 ${param.paramName} 的JSON格式不正确`);
            return;
          }
        }
      }

      OnlineApiController.testScript({
        id: dialogParams.value.formData?.id,
        scriptParam: processedParams,
      })
        .then(res => {
          runResult.value = JSON.stringify(res, null, 2);
        })
        .catch(e => {
          console.error(e);
          runResult.value = {
            error: true,
            message: e.message || '未知错误',
          };
        });
    } catch (e) {
      console.error(e);
      ElMessage.error('运行失败');
    }
  });
};
</script>

<style lang="scss" scoped>
.section-title {
  display: flex;
  align-items: center;
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #303133;

  .el-icon {
    margin-right: 8px;
    font-size: 18px;
  }
}

.action-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 24px 0;
  padding: 16px 0;
  border-top: 1px dashed #e4e7ed;
  border-bottom: 1px dashed #e4e7ed;
  .el-button {
    width: 160px;
  }
}

.result-wrapper {
  background: #f8f9fa;
  border-radius: 4px;
  margin-bottom: 20px;
}

.boolean-wrapper {
  display: flex;
  align-items: center;
}

:deep(.el-form-item__label) {
  font-weight: bold;
}

:deep(.el-input-number) {
  width: 100%;
}

:deep(.el-input-group__append) {
  padding: 0;
  width: 75px !important;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #ffffff;
}

// JSON Viewer Theme
.my-awesome-json-theme {
  width: 100%;
  font-size: 14px;
  font-family: Consolas, Menlo, Courier, monospace;
  white-space: nowrap;
  color: #525252;
  background: transparent;

  :deep(.jv-ellipsis) {
    display: inline-block;
    padding: 0 4px 2px;
    font-size: 0.9em;
    color: #999;
    background-color: #eee;
    border-radius: 3px;
    line-height: 0.9;
    vertical-align: 2px;
    cursor: pointer;
    user-select: none;
  }
  :deep(.jv-button) {
    color: #49b3ff;
  }
  :deep(.jv-key) {
    color: #111;
  }
  :deep(.jv-item) {
    &.jv-array {
      color: #111;
    }
    &.jv-boolean {
      color: #fc1e70;
    }
    &.jv-function {
      color: #067bca;
    }
    &.jv-number {
      color: #fc1e70;
    }
    &.jv-number-float {
      color: #fc1e70;
    }
    &.jv-number-integer {
      color: #fc1e70;
    }
    &.jv-object {
      color: #111;
    }
    &.jv-undefined {
      color: #e08331;
    }
    &.jv-string {
      white-space: normal;
      color: #42b983;
      word-break: break-word;
    }
  }
  :deep(.jv-code) {
    .jv-toggle {
      &::before {
        padding: 0 2px;
        border-radius: 2px;
      }
      &:hover {
        &::before {
          background: #eee;
        }
      }
    }
  }
}
</style>
